/*******************************************************************
**	FlipBook3D using Three.js, MOD3.js and Tween.js
**	Author Nikos M.
** 	url http://nikos-web-development.netai.net/
*********************************************************************/

// 3D Flip Book -------------------------------------------------------------------------------------------
var FlipBook3D=FlipBook3D || {};

// Book  Class-------------------------------------------------------------------------------------------
FlipBook3D.Book = function () {
    this.pages = null;
    this.pageWidth = 0;
    this.pageHeight = 0;
    this.currentPage = 0;
    this.flippedleft = 0;
    this.flippedright = 0;
    this.duration = 1;
    this.centerContainer = new THREE.Object3D();
    this.add(this.centerContainer);
    this.pages = [];

    //var object = new THREE.AxisHelper(100);
    //this.centerContainer.add(object);
};
FlipBook3D.Book.prototype=new THREE.Object3D();
FlipBook3D.Book.prototype.constructor=FlipBook3D.Book;
FlipBook3D.Book.prototype.getNumPages = function () {
    return (this.pages.length);
};
FlipBook3D.Book.prototype.addPage = function (pf, pb, hardness, pageColor) {
    var hardn = 0.5, pagecol = 0xeeeeee;
    if (typeof hardness != 'undefined')
        hardn = hardness;
    if (typeof pageColor != 'undefined')
        pagecol = pageColor;
    var i = this.pages.length;
	
    this.pages.push(new FlipBook3D.Page(this, i, pf, pb, hardn, pagecol));
    this.centerContainer.add(this.pages[this.pages.length - 1]);
    this.pages[this.pages.length - 1].duration = this.duration;
};

// Page Class -------------------------------------------------------------------------------------------
FlipBook3D.Page = function (book, i, matf, matb, hard, col) {
    this.book = book;
    this.matFront = matf;
    this.matBack = matb;
    this.index = i;
    this.pW = this.book.pageWidth;
    this.pH = this.book.pageHeight;
    this.nfacesw = 40; //this.pW*0.1;
    this.nfacesh = 40; //this.pH*0.1;
    this.mats = [];
    this.pageHardness = hard;
    this.duration = 1;
    
	this.angle = .25 * Math.PI * this.pW / this.pH;
    this.force = 6;
	this.to = null;
    this.flipPt = 0.3;
	
    this.mod = null;
    this.bend = null;
    this.pivot = null;
	
    this.isFlippedLeft = false;
    this.isFlippedRight = true;
    this.flippingLeft = false
    this.flippingRight = false;
    this.zz = 1;
    this.pageColor = col;
    this.sides = { bottom: 3, top: 2, right: 0, left: 1, front: 4, back: 5 };

    this.book.flippedright++;
    // align flipBook center container
    if (this.index == 0)
        this.book.centerContainer.position.x = -this.book.pageWidth * 0.5;

    // add page flip interaction TO DO..

    for (var mii = 0; mii < 6; mii++) {
        // add front - back page images
        if (mii == this.sides.front) {
            this.mats[this.sides.front] = new THREE.MeshLambertMaterial({ color: this.pageColor,  map: this.matFront, overdraw: true });
            this.mats[this.sides.front].name = "front";
        }
        else if (mii == this.sides.back) {
            this.mats[this.sides.back] = new THREE.MeshLambertMaterial({ color: this.pageColor, map: this.matBack, overdraw: true });
            this.mats[this.sides.back].name = "back";
        }
        else {
            this.mats[mii] = new THREE.MeshLambertMaterial({ color: this.pageColor });
            this.mats[mii].name = 'edge';
        }
        //this.mats[mii].wireframe = true;
        //this.mats[mii].shading = THREE.SmoothShading;
    }

    //THREE.BendShader.uniforms.colorTexture.value = this.matFront;
    //this.mats[0] = new THREE.ShaderMaterial(THREE.BendShader);

    // call super
    THREE.Mesh.call(this, new THREE.CubeGeometry(this.pW, this.pH, this.zz, this.nfacesw, this.nfacesh, 1), new THREE.MeshFaceMaterial(this.mats));
    this.overdraw = true;
    this.position.x = this.pW * 0.5;
    this.position.z = -this.zz * this.index - this.zz * 0.5;

    this.castShadow = true;
	this.receiveShadow = true;

    //var object = new THREE.AxisHelper(50);
    //this.add(object);

    // flip modifiers
    this.mod = new MOD3.ModifierStack(new MOD3.LibraryThree(), this);
    this.pivot = new MOD3.Pivot(this.position.x, 0, 0);
    this.mod.addModifier(this.pivot);
    this.mod.collapse();

    this.bend = new MOD3.Bend(0, 0, 0);
    this.bend.constraint = MOD3.ModConstant.LEFT;
    if (this.pH > this.pW)
        this.bend.switchAxes = true;
    this.mod.addModifier(this.bend);   
};
FlipBook3D.Page.prototype=new THREE.Mesh();
FlipBook3D.Page.prototype.constructor=FlipBook3D.Page;
FlipBook3D.Page.prototype.flipLeft = function (pt) {
    if (!this.isFlippedLeft && !this.flippingLeft && !this.flippingRight && this.index == this.book.flippedleft) {

        // fixing Z
        for (var i = this.book.flippedleft; i < this.book.getNumPages(); i++) {
            var page = this.book.pages[i];
            page.position.z = -page.zz * (page.index - this.book.flippedleft - 1) - page.zz * 0.5;
        }

        this.flippingLeft = true;
        //this.bend.setAngle((2 * this.flipPt - 1) * this.angle);
		
		this.castShadow = true;
		
		this.bend.constraint = MOD3.ModConstant.LEFT;
		
        this.to = { angle: this.rotation.y, t: -1, xx: 0, thiss: this };
        new TWEEN.Tween(this.to).to({ angle: -Math.PI, xx: 1, t: 1 }, this.duration * 1000).onUpdate(this.renderFlip).onComplete(this.flipFinished).start();
        
		new TWEEN.Tween({angle: .45, thiss: this}).to({angle: 0}, this.duration * 1000)
            .easing( TWEEN.Easing.Cubic.InOut ).onUpdate(function(){ this.thiss.bend.setAngle(this.angle); }).start();

		new TWEEN.Tween({rotation: 0, thiss: this}).to({rotation: -Math.PI}, this.duration * 1000)
            .easing( TWEEN.Easing.Quadratic.InOut ).onUpdate(function(){ this.thiss.rotation.y = this.rotation; }).start();

		new TWEEN.Tween({offset: 1, thiss: this}).to({offset: 0}, this.duration * 1000)
            .easing( TWEEN.Easing.Circular.Out ).onUpdate(function(){ this.thiss.bend.offset = this.offset;	}).start();

		new TWEEN.Tween({force: -2, thiss: this}).to({force: 0.009}, this.duration * 1000)
            .easing( TWEEN.Easing.Quadratic.Out ).onUpdate(function(){ this.thiss.bend.force = this.force; }).start();
        
		this.book.flippedleft++;
        this.book.flippedright--;
    }
};
FlipBook3D.Page.prototype.flipRight = function (pt) {
    if (!this.isFlippedRight && !this.flippingRight && !this.flippingLeft && this.index == this.book.getNumPages() - this.book.flippedright - 1) {
        if (pt != null) {
            //this.flipPt=pt;//e.localY/this.book.pageHeight;
        }

        // fixing Z
        for (var i = 0; i < this.book.flippedleft; i++) {
            var page = this.book.pages[i];
            page.position.z = -page.zz * (this.book.flippedleft - page.index - 2) - page.zz * 0.5;
        }

        this.flippingRight = true;
        //this.bend.setAngle((2*this.flipPt-1)*this.angle);
        //this.to = { angle: this.rotation.y, t: -1, xx: 0, thiss: this };
        //new TWEEN.Tween(this.to).to({ angle: 0, xx: 1, t: 1 }, this.duration * 1000).onUpdate(this.renderFlip).onComplete(this.flipFinished).start();
		
		this.castShadow = true;
		
		this.bend.constraint = MOD3.ModConstant.RIGHT;
		
        this.to = { angle: this.rotation.y, t: -1, xx: 0, thiss: this };
        new TWEEN.Tween(this.to).to({ angle: -Math.PI, xx: 1, t: 1 }, this.duration * 1000).onUpdate(this.renderFlip).onComplete(this.flipFinished).start();
        
		new TWEEN.Tween({angle: Math.PI+.45, thiss: this}).to({angle: Math.PI}, this.duration * 1000)
            .easing( TWEEN.Easing.Cubic.InOut ).onUpdate(function(){ this.thiss.bend.setAngle(this.angle); }).start();

		new TWEEN.Tween({rotation: -Math.PI, thiss: this}).to({rotation: 0}, this.duration * 1000)
            .easing( TWEEN.Easing.Quadratic.InOut ).onUpdate(function(){ this.thiss.rotation.y = this.rotation; }).start();

		new TWEEN.Tween({offset: -1, thiss: this}).to({offset: 0}, this.duration * 1000)
            .easing( TWEEN.Easing.Circular.Out ).onUpdate(function(){ this.thiss.bend.offset = this.offset;	}).start();

		new TWEEN.Tween({force: 2, thiss: this}).to({force: -0.009}, this.duration * 1000)
            .easing( TWEEN.Easing.Quadratic.Out ).onUpdate(function(){ this.thiss.bend.force = this.force; }).start();        
		
		this.book.flippedleft--;
        this.book.flippedright++;
    }
};
FlipBook3D.Page.prototype.renderFlip = function () {
    
    // align flipBook to center
    if (this.thiss.flippingLeft && this.thiss.index == 0 && this.thiss.book.getNumPages() > 1)
        this.thiss.book.centerContainer.position.x = (1 - this.xx) * this.thiss.book.centerContainer.position.x;
    else if (this.thiss.flippingLeft && this.thiss.index == this.thiss.book.getNumPages() - 1)
        this.thiss.book.centerContainer.position.x = (1 - this.xx) * this.thiss.book.centerContainer.position.x + this.xx * this.thiss.book.pageWidth * 0.5;
    else if (this.thiss.flippingRight && this.thiss.index == 0)
        this.thiss.book.centerContainer.position.x = (1 - this.xx) * this.thiss.book.centerContainer.position.x - this.xx * this.thiss.book.pageWidth * 0.5;
    else if (this.thiss.flippingRight && this.thiss.index == this.thiss.book.getNumPages() - 1)
        this.thiss.book.centerContainer.position.x = (1 - this.xx) * this.thiss.book.centerContainer.position.x;    

    // flip page
    var p2 = Math.PI * 0.5;
    var tt = (1 - Math.abs(this.t));
	
    //this.thiss.rotation.y = this.angle;
    //this.thiss.bend.force = ((Math.abs(this.angle)-p2)/p2)*tt*this.thiss.force*(1-this.thiss.pageHardness);
    //this.thiss.bend.offset = (1-tt)*0.6+tt*0.5;
	
	//this.thiss.bend.constraint = MOD3.ModConstant.LEFT;
	//this.thiss.bend.force = -6 * (1-this.xx);
	//this.thiss.bend.offset = 0.5;
	//this.thiss.bend.setAngle(.65 * (1-this.xx));
	
    this.thiss.mod.apply();
};
FlipBook3D.Page.prototype.flipFinished = function () {

    if (this.thiss.flippingLeft) {
        this.thiss.flippingLeft = false;
        this.thiss.isFlippedLeft = true;
        this.thiss.flippingRight = false;
        this.thiss.isFlippedRight = false;
    }
    else if (this.thiss.flippingRight) {
        this.thiss.flippingLeft = false;
        this.thiss.isFlippedRight = true;
        this.thiss.flippingRight = false;
        this.thiss.isFlippedLeft = false;
    }

	//this.thiss.castShadow = false;
	
    // fixing Z
    var _book = this.thiss.book;
    for (var i = 0; i < _book.getNumPages(); i++) {
        var _page = _book.pages[i];
        _page.position.z = -_page.zz * (_page.index < _book.flippedleft ? (_book.flippedleft - 1) - _page.index : _page.index - _book.flippedleft) - _page.zz * 0.5;
    
		_page.bend.constraint = MOD3.ModConstant.LEFT;
		_page.bend.force = 0;
		_page.bend.setAngle(0);
		_page.bend.offset = 0;	
		_page.mod.apply();
	}
	/*
	for (var i = 0; i < _book.getNumPages(); i++) {
        var _page = _book.pages[i];
		if(_page.index < _book.flippedleft) {
			_page.bend.constraint = MOD3.ModConstant.RIGHT;
			_page.bend.force = -3.0;
			_page.bend.setAngle(0);
			_page.bend.offset = 0.1;
		} else {
			_page.bend.constraint = MOD3.ModConstant.LEFT;
			_page.bend.force = 3.0;
			_page.bend.setAngle(Math.PI);
			_page.bend.offset = -0.1;
		}        
		_page.mod.apply();
    }*/	
};
